/*
 * NavigateForm.java
 *
 * Created on 15 avril 2007, 13:17
 */

package courselog;

import courselog.maputils.TiledMap;
import courselog.maputils.TiledMapBrowser;
import ewe.filechooser.FileChooser;
import ewe.fx.Color;
import ewe.fx.Font;
import ewe.fx.Graphics;
import ewe.fx.IImage;
import ewe.fx.IconAndText;
import ewe.fx.Image;
import ewe.fx.Pen;
import ewe.fx.Rect;
import ewe.io.File;
import ewe.sys.mThread;
import ewe.ui.CellConstants;
import ewe.ui.ControlConstants;
import ewe.ui.ControlEvent;
import ewe.ui.Event;
import ewe.ui.Form;
import ewe.ui.Gui;
import ewe.ui.Menu;
import ewe.ui.MenuEvent;
import ewe.ui.MenuItem;
import ewe.ui.MessageBox;
import ewe.ui.WindowEvent;
import ewe.ui.mLabel;

/**
 * Navigation panel for the application.
 * @author rigal
 */
public class NavigateForm extends CourseLogAppForm {
    
    /** Color for screen data background */
    public static final Color COLOROSDBACKGROUND=Color.DarkBlue;
    
    /** Color for screen data foreground */
    public static final Color COLOROSDFOREGROUND=Color.White;
    
    public final IconAndText SWAPFOLLOW=new IconAndText("Follow position$F",
            "res/navigateState.png",Color.White,null);
    public final IconAndText SWAPFREE=new IconAndText("Free moves$F",
            "res/navigateState.png",Color.White,null);
    
    public final IconAndText WPLOCKED=new IconAndText("Unlock waypoints$K",
            "res/lockunlocked.png",Color.White,null);
    public final IconAndText WPUNLOCKED=new IconAndText("Lock waypoints$K",
            "res/locklocked.png",Color.White,null);
    
    protected IconAndText iconWaypoints_ON;
    protected IconAndText iconWaypoints_OFF;
    protected IconAndText iconTrack_ON;
    protected IconAndText iconTrack_OFF;
    
    protected PullDownForKey pdMapActions;
    protected PullDownForKey bGoto;
    protected TiledMapBrowser tmb;
    
    protected MainApplication myApp=null;
    
    protected Menu menuWaypointActions;
    protected Menu menuNoWaypointActions;
    
    protected Menu myMenuMapActions;
    protected MenuItem miSwapState=new MenuItem(SWAPFREE.text);
    protected MenuItem miSwapLock=new MenuItem(WPLOCKED.text,WPLOCKED.icon);
    protected MenuItem miDispWaypoints=new MenuItem();
    protected MenuItem miDispTrack=new MenuItem();
    protected Menu menuShow;
    protected MenuItem miDelete=new MenuItem("Delete waypoint$W",
            "ewe/deletesmall.bmp",Color.White);
    protected MenuItem miInvert=new MenuItem("Invert $I","res/invert.png",Color.White);
    
    public Menu menuPoint;
    public Menu menuDisplay;
    
    // CONSTRUCTORS
    
    public NavigateForm(MainApplication myApp) {
        this.myApp=myApp;
        this.setTitle("Navigation - Courselog");
        Form.globalIcon = myApp.myAppGlobalIcon;
        
        tmb=new TiledMapBrowser(myApp.getMyMapDir());
        
        buildWPAndTrackIcons();
        
        MenuItem miReload=new MenuItem("ReLoad$L","res/reloadsmall.png",Color.White);
        miReload.action="L";
        MenuItem miScaleOne=new MenuItem("Rescale 1$R","res/scaleone.png",Color.White);
        miScaleOne.action="1";
        MenuItem miScaleMin=new MenuItem("Rescale Min","res/scalemax.png",Color.White);
        miScaleMin.action="MIN";
        MenuItem miScaleMax=new MenuItem("Rescale Max","res/scalemin.png",Color.White);
        miScaleMax.action="MAX";
        MenuItem miSeparator=new MenuItem("-");
        miSwapState.iconize(SWAPFREE.text,SWAPFREE.icon,true);
        miSwapState.action="F";
        miSwapLock.action="K";
        miDispWaypoints.iconize(iconWaypoints_ON.text,iconWaypoints_ON.icon,true);
        miDispWaypoints.action="W";
        miDispTrack.iconize(iconTrack_ON.text,iconTrack_ON.icon,true);
        miDispTrack.action="T";
        MenuItem[] tmiShow=new MenuItem[]{miDispWaypoints,miDispTrack};
        menuShow=new Menu(tmiShow,"Show");
//        menuShow.modify(Menu.Disabled,0);
        MenuItem miShow=new MenuItem("Show");
        miShow.subMenu=menuShow;
        MenuItem miOpen=new MenuItem("Open waypoints$O","ewe/opensmall.bmp",Color.White);
        miOpen.action="O";
        MenuItem miSave=new MenuItem("Save waypoints$S","ewe/savesmall.bmp",Color.White);
        miSave.action="S";
        MenuItem miNew=new MenuItem("New waypoints$N","ewe/newsmall.bmp",Color.White);
        miNew.action="Z";
        MenuItem miExit=new MenuItem("Exit$x","ewe/exitsmall.bmp",Color.White);
        MenuItem[] tmiMapActions=new MenuItem[]{miScaleOne,miReload,miScaleMax,
        miScaleMin,miSeparator,
        miSwapState,miSwapLock,miShow,miSeparator,miOpen,miSave,miNew};
        
        Menu menuFileActions;
        /** menu for actions */
        MenuItem miOptions=new MenuItem("Options$O","ewe/optionssmall.bmp",Color.White);
        miOptions.action="P";
        MenuItem miCalibrate=new MenuItem("Calibrate$C","res/iconcalibsmall.png",Color.White);
        miCalibrate.action="C";
        MenuItem miDistance=new MenuItem("Distance$D","res/courselogsmall.png",Color.White);
        miDistance.action="D";
        MenuItem miConvert=new MenuItem("Convert$v","res/convertsmall.png",Color.White);
        miConvert.action="V";
        miExit.action="X";
        MenuItem[] tmiFileActions=new MenuItem[]{miDistance,miOptions,
        miCalibrate,miConvert,miSeparator,miExit};
        
        MenuItem miSelectNext=new MenuItem("Set Next$X",
                "ewe/rightarrowsmall.bmp",Color.White);
        miSelectNext.action="E";
        miDelete.action="R";
        miInvert.action="I";
        MenuItem[] tmiWPMenu=new MenuItem[]{miSelectNext,miDelete,miInvert};
        menuWaypointActions=new Menu(tmiWPMenu,"Waypoint");
        menuWaypointActions.addListener(this);
        
        MenuItem miCenterHere=new MenuItem("Center here$H",
                "ewe/editsmall.bmp",Color.White);
        miCenterHere.action="H";
        MenuItem[] tmiNoWPMenu=new MenuItem[]{miCenterHere,miScaleOne,
        miDispWaypoints,miDispTrack};
        menuNoWaypointActions=new Menu(tmiNoWPMenu,"Map");
        menuNoWaypointActions.addListener(this);
        this.addDirectly(menuWaypointActions);
        this.addDirectly(menuNoWaypointActions);
        tmb.setPenHeldMenus(menuWaypointActions,menuNoWaypointActions);
        mLabel mlP=new mLabel(1,10);
        Font fLab=mlP.getFont();
        fLab=fLab.changeStyle(Font.BOLD);
        Font fontOSD=this.getFont();
        fontOSD=fontOSD.changeStyle(Font.BOLD);
        mlP.backGround=COLOROSDBACKGROUND;
        mlP.foreGround=COLOROSDFOREGROUND;
        mlP.setFont(fLab);
        mLabel mlT=new mLabel(1,10);
        mlT.setFont(fLab);
        mlT.backGround=COLOROSDBACKGROUND;
        mlT.foreGround=COLOROSDFOREGROUND;
        mlP.spacing=0;
        mlT.spacing=0;
        tmb.setDisplays(mlP, mlT);
        
        myMenuMapActions=new Menu(tmiMapActions,"Map actions");
        pdMapActions=new PullDownForKey("Actions",myMenuMapActions);
        MenuEvent meSwap=new MenuEvent(MenuEvent.SELECTED,pdMapActions,miSwapState);
        tmb.setSwapStateHandler(this,meSwap);
        
        menuFileActions=new Menu(tmiFileActions,"GO TO");
        bGoto=new PullDownForKey("GO TO",menuFileActions);
        
        ActionKeysDispatcher akd= new ActionKeysDispatcher();
        akd.setLeftAndRight(bGoto,pdMapActions);
        bGoto.setActionKeyListener(akd);
        pdMapActions.setActionKeyListener(akd);
        
        addLast(mlP,CellConstants.CENTER,CellConstants.FILL);
        addLast(mlT,CellConstants.CENTER,CellConstants.FILL);
        courseLogAppFormSetup(bGoto,pdMapActions,tmb);
        tmb.setActionKeyDispatcher(akd);
//        setMyTMState(tmb.myState);
    }
    
    // ACCESSORS
    
    /**
     * Set the current TiledMapBrowser state and update menus.
     * @param newState value, one of TiledMapBrowser.STATE_xxx values.
     */
    public void setMyTMState(int newState) {
        tmb.myState=newState;
        if((tmb.myState&TiledMapBrowser.STATE_DISPLAYWP)!=0) {
            miDispWaypoints.iconize(iconWaypoints_OFF.text,iconWaypoints_OFF.icon,true);
        }else{
            miDispWaypoints.iconize(iconWaypoints_ON.text,iconWaypoints_ON.icon,true);
        }
        if((tmb.myState&TiledMapBrowser.STATE_DISPLAYTR)!=0) {
            miDispTrack.iconize(iconTrack_OFF.text,iconTrack_OFF.icon,true);
        }else{
            miDispTrack.iconize(iconTrack_ON.text,iconTrack_ON.icon,true);
        }
        if((tmb.myState&TiledMapBrowser.STATE_FOLLOW)!=0) {
            miSwapState.iconize(SWAPFREE.text,SWAPFREE.icon,true);
//            menuShow.modify(Menu.Disabled,0);
            
        }else {
            miSwapState.iconize(SWAPFOLLOW.text,SWAPFOLLOW.icon,true);
//            menuShow.modify(0,Menu.Disabled);
        }
        if((tmb.myState&TiledMapBrowser.STATE_LOCKWP)!=0) {
            miSwapLock.iconize(WPLOCKED.text,WPLOCKED.icon,true);
            miDelete.modifiers |= MenuItem.Disabled;
            miInvert.modifiers |= MenuItem.Disabled;
        }else {
            miSwapLock.iconize(WPUNLOCKED.text,WPUNLOCKED.icon,true);
            miDelete.modifiers &= ~MenuItem.Disabled;
            miInvert.modifiers &= ~MenuItem.Disabled;
        }
//        pdMapActions.redisplay();
        miSwapState.action="F";
        miSwapLock.action="K";
        tmb.updateDisplayedImage(null,0);
    }
    
    // CLASS METHODS
    
    /**
     * Build the icons for the waypoints and track menus.
     * This is done dynamically to allow further user-selected waypoint and
     * track colors.
     */
    public void buildWPAndTrackIcons() {
        Image img=new Image(16,16,Image.ALPHA_CHANNEL);
        img.transparent=Color.White;
        Graphics gI=new Graphics(img);
        gI.setColor(Color.White);
        gI.fillRect(0,0,16,16);
        gI.setPen(TiledMapBrowser.PENNONVISITEDWP);
        int[] xL=new int[]{8,14,2,12,2};
        int[] yL=new int[]{15,12,6,6,2};
        gI.drawLines(xL,yL,xL.length);
        img.freeze();
        iconWaypoints_ON=new IconAndText(img,"Waypoints on$W",null);
        img=new Image(img,Image.EXACT_TYPE_IMAGE);
        gI.free();
        gI=new Graphics(img);
        Pen penCross=new Pen(Color.Black,Pen.SOLID,3);
        gI.setPen(penCross);
        gI.drawLine(1,15,15,1);
        gI.drawLine(1,1,15,15);
        img.freeze();
        iconWaypoints_OFF=new IconAndText(img,"Waypoints off$W",null);
        gI.free();
        
        img=new Image(16,16,Image.ALPHA_CHANNEL);
        img.transparent=Color.White;
        gI=new Graphics(img);
        gI.setColor(Color.White);
        gI.fillRect(0,0,16,16);
        gI.setPen(TiledMapBrowser.PENTRACK);
        gI.drawLines(xL,yL,xL.length);
        img.freeze();
        iconTrack_ON=new IconAndText(img,"Track on$T",null);
        img=new Image(img,Image.EXACT_TYPE_IMAGE);
        gI.free();
        gI=new Graphics(img);
        gI.setPen(penCross);
        gI.drawLine(1,15,15,1);
        gI.drawLine(1,1,15,15);
        img.freeze();
        iconTrack_OFF=new IconAndText(img,"Track off$T",null);
    }
    
    /** Triggers an exit from the application
     * @param nextState Next application state.
     */
    public void tryExitForm(int nextState) {
        if(mayNotLoseWaypoints()) return;
        
        myApp.myNextActivePanel=nextState;
        tmb.setActive(false);
        exit(Form.IDOK);
    }
    
    public void tryOpenWaypoints() {
        if(mayNotLoseWaypoints()) return;
        
        String initDir=myApp.myLogFileName;
        if(myApp.myLastWaypoints!=null) {
            initDir=myApp.myLastWaypoints;
        }
        FileChooser wpCh= new FileChooser(FileChooser.OPEN,initDir);
        wpCh.switchMultiSelect(false);
        int resDlg= wpCh.execute();
        if(resDlg!=FileChooser.IDOK) return;
        
        File fWp=wpCh.getChosenFile();
        myApp.myLastWaypoints=fWp.getFullPath();
        tmb.loadWaypoints(fWp);
        tmb.myState &= ~TiledMapBrowser.STATE_DISPLAYWP;
        swapWaypointsDisplay();
        Gui.takeFocus(tmb,Gui.ByRequest);
    }
    
    /**
     * Reset the waypoints.
     */
    public void tryNewWaypoints() {
        if(mayNotLoseWaypoints()) return;
        
        tmb.resetWaypoints();
        setMyTMState(tmb.myState);
        myApp.myLastWaypoints=null;
    }
    
    public void trySaveWaypoints() {
        if(!tmb.myIsWaypointsChanged) return;
        if(tmb.myTrWaypoints.getSize()<1) return;
        
        String initDir=myApp.myLogFileName;
        if(myApp.myLastWaypoints!=null) {
            initDir=myApp.myLastWaypoints;
        }
        FileChooser wpCh= new FileChooser(FileChooser.SAVE,initDir);
        wpCh.switchMultiSelect(false);
        int resDlg= wpCh.execute();
        if(resDlg!=FileChooser.IDOK) return;
        
        File fWp=wpCh.getChosenFile();
        myApp.myLastWaypoints=fWp.getFullPath();
        tmb.saveWaypoints(fWp);
        Gui.takeFocus(tmb,Gui.ByRequest);
    }
    
    public void swapWaypointsDisplay() {
        if((tmb.myState&tmb.STATE_DISPLAYWP)==0) {
            miDispWaypoints.iconize(iconWaypoints_OFF.text,iconWaypoints_OFF.icon,true);
        }else{
            miDispWaypoints.iconize(iconWaypoints_ON.text,iconWaypoints_ON.icon,true);
        }
        tmb.myState ^= tmb.STATE_DISPLAYWP;
        tmb.updateDisplayedImage(null,tmb.OPT_WPUNCHANGED);
    }
    
    public void swapTrackDisplay() {
        if((tmb.myState&tmb.STATE_DISPLAYTR)==0) {
            miDispTrack.iconize(iconTrack_OFF.text,iconTrack_OFF.icon,true);
        }else{
            miDispTrack.iconize(iconTrack_ON.text,iconTrack_ON.icon,true);
        }
        tmb.myState ^= tmb.STATE_DISPLAYTR;
        tmb.updateDisplayedImage(null,0);
    }
    
    /**
     * Swap the waypoints mode from locked to unlocked or vice-versa.
     */
    public void swapLockedWP() {
        tmb.setWPLocked((tmb.myState&tmb.STATE_LOCKWP)==0);
        setMyTMState(tmb.myState);
    }
    
    public void swapState() {
        if((tmb.myState&tmb.STATE_FOLLOW)==0) {
            miSwapState.iconize(SWAPFREE.text,SWAPFREE.icon,true);
//            menuShow.modify(Menu.Disabled,0);
            
        }else {
            miSwapState.iconize(SWAPFOLLOW.text,SWAPFOLLOW.icon,true);
//            menuShow.modify(0,Menu.Disabled);
        }
        pdMapActions.redisplay();
        miSwapState.action="F";
        tmb.myState ^=tmb.STATE_FOLLOW;
        tmb.repaint();
    }
    
    public void rescaleOne() {
        tmb.reScaleOne();
        Gui.takeFocus(tmb,Gui.ByRequest);
    }
    
    public void rescaleMax() {
        tmb.reScaleMax();
        Gui.takeFocus(tmb,Gui.ByRequest);
    }
    
    public void rescaleMin() {
        tmb.reScaleMin();
        Gui.takeFocus(tmb,Gui.ByRequest);
    }
    
    public void reLoad() {
        tmb.setTiledMapFrom(myApp.getMyMapDir());
        rescaleOne();
    }
    
    /**
     * Invert the waypoints track.
     */
    public void invertTrack() {
        tmb.invertWaypoints();
    }
    
    /**
     * Remove last waypoint selected via pen held.
     */
    public void removeWaypoint() {
        tmb.removePenHeldWaypoint();
    }
    
    /**
     * Select Next waypoint to aim to, designated via pen held.
     */
    public void selectNextWaypoint() {
        tmb.visitPenHeldWaypoint();
    }
    
    /**
     * Select Next position to center the map on.
     */
    public void recenterOnPenHeld() {
        tmb.reCenterOnPenHeldPoint();
    }
    
    /** Ask whether the user accepts to lose waypoints.
     * @return true if the user refuses to lose waypoints.
     */
    public boolean mayNotLoseWaypoints() {
        int resDlg= MessageBox.IDYES;
        if(tmb.myIsWaypointsChanged) {
            resDlg=(new MessageBox("Save current Waypoints",
                    "Current waypoints are not saved.\nYou may Lose changes.\n"
                    +"Do it anyway?",
                    MessageBox.MBYESNO)).execute();
        }
        return (resDlg!=MessageBox.IDYES);
    }
    
    public void executeAction(String actString) {
        if(actString.equals("1")) rescaleOne();
        if(actString.equals("MIN")) rescaleMin();
        if(actString.equals("MAX")) rescaleMax();
        else if(actString.equals("C")) tryExitForm(MainApplication.ACTIVECALIBRATION);
        else if(actString.equals("D")) tryExitForm(MainApplication.ACTIVEDISTANCE);
        else if(actString.equals("E")) selectNextWaypoint();
        else if(actString.equals("F")) swapState();
        else if(actString.equals("H")) recenterOnPenHeld();
        else if(actString.equals("I")) invertTrack();
        else if(actString.equals("K")) swapLockedWP();
        else if(actString.equals("L")) reLoad();
        else if(actString.equals("O")) tryOpenWaypoints();
        else if(actString.equals("P")) tryExitForm(MainApplication.ACTIVEOPTIONS);
        else if(actString.equals("R")) removeWaypoint();
        else if(actString.equals("S")) trySaveWaypoints();
        else if(actString.equals("T")) swapTrackDisplay();
        else if(actString.equals("V")) tryExitForm(MainApplication.ACTIVECONVERT);
        else if(actString.equals("W")) swapWaypointsDisplay();
        else if(actString.equals("X")) tryExitForm(-1);
        else if(actString.equals("Z")) tryNewWaypoints();
    }
    
    // OVERIDDEN METHODS
    
    public void onEvent(Event ev) {
        try {
            if(!tmb.isActive()) { // I get event so I am active!
                tmb.setActive(true);
            }
            
            if((ev.target==dbgL.getLogControl())&&(ev.type==ControlEvent.FOCUS_IN)) {
                Gui.takeFocus(tmb,ByRequest);
            }
            if((ev.target==this)&&(ev.type==ControlEvent.FOCUS_IN)) {
                Gui.takeFocus(defC,ControlConstants.ByRequest);
                myApp.myNextActivePanel=-1;
            }
            if((ev.target == bGoto)||(ev.target==pdMapActions)||
                    (ev.target==menuWaypointActions)||
                    (ev.target==menuNoWaypointActions)) {
                if(ev.type==MenuEvent.SELECTED) {
//                CourseLogAppForm.dbgL.addToLog("\n pressed:"+ev.target+" item "+pdFileActions.getLastSelected());
                    MenuEvent mEv=(MenuEvent) ev;
                    final MenuItem selItem= (MenuItem) mEv.selectedItem;
//                CourseLogAppForm.dbgL.addToLog("\n selected:"+selItem.action);
                    mThread actThread= new mThread(new Runnable() {
                        public void run() {
                            executeAction(selItem.action);
                            //updateFormState();
                        }
                    });
                    actThread.start();
                }
            }
        } catch (NullPointerException ex) {
            CourseLogAppForm.dbgL.addExceptionToLog(ex);
        } catch (IndexOutOfBoundsException ex) {
            CourseLogAppForm.dbgL.addExceptionToLog(ex);
        } catch (ClassCastException ex) {
            CourseLogAppForm.dbgL.addExceptionToLog(ex);
        }
    }
    
}